﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.DatabaseServices;

namespace AutoCADDotNetLibrary
{
    /// <summary>
    /// 表扩展
    /// </summary>
    public static class TableExtention
    {
        /// <summary>
        /// 根据9个表类的类型变成相应的表
        /// </summary>
        /// <param name="db"></param>
        /// <param name="type"></param>
        /// <param name="mode"></param>
        /// <returns></returns>
        private static SymbolTable ToTable(Database db, Type type, OpenMode mode)
        {
            Transaction trans = db.TransactionManager.TopTransaction;

            SymbolTable table;
            if (type == typeof(BlockTableRecord))
            {
                table = trans.GetObject(db.BlockTableId, mode) as SymbolTable;
            }
            else if (type == typeof(DimStyleTableRecord))
            {
                table = trans.GetObject(db.DimStyleTableId, mode) as SymbolTable;
            }
            else if (type == typeof(LayerTableRecord))
            {
                table = trans.GetObject(db.LayerTableId, mode) as SymbolTable;
            }
            else if (type == typeof(LinetypeTableRecord))
            {
                table = trans.GetObject(db.LinetypeTableId, mode) as SymbolTable;
            }
            else if (type == typeof(RegAppTableRecord))
            {
                table = trans.GetObject(db.RegAppTableId, mode) as SymbolTable;
            }
            else if (type == typeof(TextStyleTableRecord))
            {
                table = trans.GetObject(db.TextStyleTableId, mode) as SymbolTable;
            }
            else if (type == typeof(UcsTableRecord))
            {
                table = trans.GetObject(db.UcsTableId, mode) as SymbolTable;
            }
            else if (type == typeof(ViewportTableRecord))
            {
                table = trans.GetObject(db.ViewportTableId, mode) as SymbolTable;
            }
            else if (type == typeof(ViewTableRecord))
            {
                table = trans.GetObject(db.ViewTableId, mode) as SymbolTable;
            }
            else
            {
                throw new Exception("错误原因：9表中不应有" + type.Name);
            }
            return table;
        }

        /// <summary>
        /// 得到表记录集合
        /// </summary>
        /// <typeparam name="T">表记录(9个表之一)</typeparam>
        /// <param name="db">数据库</param>
        /// <param name="mode">打开模式</param>
        /// <returns>表记录集合</returns>
        public static IEnumerable<T> GetTableRecords<T>(this Database db, OpenMode mode) where T : SymbolTableRecord
        {
            Transaction trans = db.TransactionManager.TopTransaction;

            SymbolTable table = ToTable(db, typeof(T), OpenMode.ForRead);

            return table.Cast<ObjectId>().Select(x => trans.GetObject(x, mode)).Cast<T>();
        }

        /// <summary>
        /// 得到表记录
        /// </summary>
        /// <typeparam name="T">表记录(9个表之一)</typeparam>
        /// <param name="db">数据库</param>
        /// <param name="mode">打开模式</param>
        /// <param name="tableRecordName">表记录名</param>
        /// <returns>表记录</returns>
        public static T GetTableRecord<T>(this Database db, string tableRecordName, OpenMode mode) where T : SymbolTableRecord
        {
            Transaction trans = db.TransactionManager.TopTransaction;

            SymbolTable table = ToTable(db, typeof(T), OpenMode.ForRead);

            if (table.Has(tableRecordName))
            {
                return trans.GetObject(table[tableRecordName], mode) as T;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 添加表记录
        /// </summary>
        /// <typeparam name="T">表记录(9个表之一)</typeparam>
        /// <param name="db">数据库</param>
        /// <param name="tableRecordName">表记录名称</param>
        /// <param name="act">在加入数据库前的赋值操作</param>
        /// <returns>表记录</returns>
        public static T AddTableRecord<T>(this Database db, string tableRecordName, Action<T> act = null) where T : SymbolTableRecord, new()
        {
            Transaction trans = db.TransactionManager.TopTransaction;

            SymbolTable table = ToTable(db, typeof(T), OpenMode.ForWrite);

            if (!table.Has(tableRecordName))
            {
                T tr = new T();
                tr.Name = tableRecordName;
                act?.Invoke(tr);
                table.Add(tr);
                trans.AddNewlyCreatedDBObject(tr, true);

                return tr;
            }
            else
            {
                return trans.GetObject(table[tableRecordName], OpenMode.ForWrite) as T;
            }
        }

        /// <summary>
        /// 是否能删除（适合删一个的时候）
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsCanDelete(this SymbolTableRecord str)
        {
            ObjectIdCollection oc = new ObjectIdCollection
            {
                str.ObjectId
            };

            str.Database.Purge(oc);

            if (oc.Count > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 得到能够删除的表（适合删很多的时候）
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static IEnumerable<SymbolTableRecord> CanDeleteList(this IEnumerable<SymbolTableRecord> str)
        {
            ObjectIdCollection oc = new ObjectIdCollection(str.Select(x => x.ObjectId).ToArray());

            Database db = str.FirstOrDefault()?.Database;
            if (db == null)
                return null;
            db.Purge(oc);

            return oc.Cast<ObjectId>().Select(x => str.First(y => y.ObjectId == x));
        }
    }
}
